package com.huiHang.auth.api;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huiHang.auth.api.hystrix.AuthApiFailBack;
import com.huiHang.auth.entity.User;
import com.huiHang.auth.entity.UserBasicInfo;
import com.huiHang.auth.entity.UserPrivateInfo;
import com.huiHang.auth.pojo.dto.UserLoginDTO;
import com.huiHang.auth.pojo.dto.UserRegistrationDTO;
import com.huiHang.auth.service.IUserBasicInfoService;
import com.huiHang.auth.service.IUserPrivateInfoService;
import com.huiHang.auth.service.IUserService;
import com.huiHang.auth.service.SmsService;
import com.huihang.core.utils.EncryptUtils;
import com.huihang.core.utils.Fun;
import com.huihang.core.utils.Result;
import com.huihang.core.utils.ResultCode;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
public class Auth extends AuthApiFailBack implements AuthApi {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private SmsService smsService;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private IUserBasicInfoService iUserBasicInfoService;

    @Autowired
    private IUserPrivateInfoService iUserPrivateInfoService;

    @Override
    @CircuitBreaker(name = "auth", fallbackMethod = "operatorLoginFallback")
    public String operatorLogin() {
        try {
            throw new Exception("服务异常");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    @CircuitBreaker(name = "auth", fallbackMethod = "verificationCode")
    public Result<String> verificationCode(String phone) {
        //如果当前存在验证码要删除，之前得验证码失效
        redisTemplate.opsForValue().getOperations().delete(phone);
        //用于判断验证码获取得次数，验证码对我来说都是钱，我必须严格把控发送次数
        String phoneRf = phone + "rf";
        Boolean hasKey = redisTemplate.hasKey(phoneRf);
        int requestFrequency = Integer.parseInt(Objects.requireNonNull(redisTemplate.opsForValue().get(phoneRf)));
        if (Boolean.TRUE.equals(hasKey) && requestFrequency > 5) {
            return Result.error(ResultCode.CAPTCHA_TOO_MANY_REQUESTS_ERROR.getCode());
        }
        Random random = new Random();
        int result = random.nextInt(9999);
        redisTemplate.opsForValue().set(phone, String.valueOf(result), 600, TimeUnit.SECONDS);
        int updatedFrequency = requestFrequency + 1;
        redisTemplate.opsForValue().set(phoneRf, String.valueOf(updatedFrequency), 2, TimeUnit.HOURS);
        smsService.sendSmsMsg(phone, "1", new String[]{String.valueOf(result),"十分钟"});
        return Result.success(String.valueOf(result));
    }

    @Override
    @CircuitBreaker(name = "auth", fallbackMethod = "userRegistration")
    public Result<String> userRegistration(UserRegistrationDTO dto) {
        User user = new User();
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setPhone(EncryptUtils.aesEncrypt(dto.getPhone()));
        // 要对密码进行加密加盐 也可以设置得更加复杂一些，就算别人获取到我们库里面得账号和密钥了。也难以破解我们得密码。md5 现在数字都是可逆得了，非数字得我觉得也有可能是早晚得事情，所以加盐是非常不错得事情
        user.setUserPassword(EncryptUtils.md5(dto.getUserPassword()+dto.getPhone()));
        user.setLastLogTime(LocalDateTime.now());
        iUserService.save(user);
        UserBasicInfo userBasicInfo = new UserBasicInfo();
        userBasicInfo.setId(user.getId());
        userBasicInfo.setNickname(dto.getNickname());
        iUserBasicInfoService.save(userBasicInfo);
        UserPrivateInfo userPrivateInfo = new UserPrivateInfo();
        userPrivateInfo.setId(user.getId());
        userPrivateInfo.setCreateTime(LocalDateTime.now());
        userPrivateInfo.setUpdateTime(LocalDateTime.now());
        userPrivateInfo.setPhone(EncryptUtils.aesEncrypt(dto.getPhone()));
        userPrivateInfo.setIdCardNumber(EncryptUtils.aesEncrypt(dto.getIdCardNumber()));
        userPrivateInfo.setRealName(dto.getRealName());
        iUserPrivateInfoService.save(userPrivateInfo);
        return Result.success(user.getId().toString());
    }

    @Override
    public Result<String> userLogin(UserLoginDTO dto) {
        User user = iUserService.list(Wrappers.lambdaQuery(User.class).
                eq(User::getId, dto.getAccountNumber()).or().
                eq(User::getPhone, EncryptUtils.aesEncrypt(dto.getAccountNumber())).orderByDesc(User::getCreateTime)).stream().findFirst().orElse(null);

        if (Fun.isEmpty(user)){
            return Result.error(ResultCode.FAIL_LOGIN.getCode());
        }
        String decrypt = EncryptUtils.aesDecrypt(user.getPhone());
        String password = EncryptUtils.md5(dto.getPassword()+decrypt);
        if (user.getUserPassword().equals(password)){
            return Result.success("登录成功");
        }
        return Result.error(ResultCode.FAIL_LOGIN.getCode());
    }
}
